package edu.uw.cs.cse461.sp12.OSConsoleApps;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.json.JSONException;
import org.json.JSONObject;

import edu.uw.cs.cse461.sp12.OS.RPCCallerSocket;
import edu.uw.cs.cse461.sp12.util.Log;

public class Ping implements OSConsoleApp {
	// I'm using the android-like Log.x() functions for debugging output, even for console apps
	private static final String TAG="PingConsole";
	
	public static final int PING_CALLS = 5;
	
	// OSConsoleApp's must have a constructor taking no arguments
	public Ping() {
	}
	
	public String appname() {
		return "ping";
	}
	
	public void run() {
		try {
			// Eclipse doesn't support System.console()
			BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
			while ( true ) {
				try {
					System.out.print("Enter a host ip, or exit to exit: ");
					String targetIP = console.readLine();
					if ( targetIP == null ) targetIP = "";
					else if ( targetIP.equals("exit")) break;

					System.out.print("Enter the RPC port, or empty line to exit: ");
					String targetPort = console.readLine();
					if ( targetPort == null || targetPort.isEmpty() ) continue;

					System.out.println("Pinging " + targetIP + ":");
					
					// Array for holding ping times
					int[] pingTimes = new int[PING_CALLS];
					
					for (int i = 0; i < PING_CALLS; i++){
						// Add duration to array of times
						pingTimes[i] = performCall(targetIP, targetIP, targetPort);
						
						// Output time for specific ping
						System.out.println("\tPing " + (i + 1) + " time: " + pingTimes[i] + "ms");
					}
					
					outputFinalResults(pingTimes);

				} catch (Exception e) {
					System.out.println("Exception: " + e.getMessage());
				}
			}
		} catch (Exception e) {
			Log.e(TAG, "EchoConsole.run() caught exception: " +e.getMessage());
		}
	}
	
	public static int performCall(String host, String ip, String port) throws IOException {
		try {
			long startTime;
			long endTime;
			startTime = System.currentTimeMillis();		// start timer
			try {
				RPCCallerSocket socket = new RPCCallerSocket(host, ip, port);
				socket.invoke("echo", "echo", new JSONObject().put("msg", "") );
			} finally {
				endTime = System.currentTimeMillis();	// end timer
			}
			
			return (int)(endTime - startTime);
		} catch (JSONException e) {
			String errorMessage = "Could not performCall (JSONException): " + e.getMessage();
			Log.e(TAG, errorMessage);
			throw new IOException(errorMessage);
		}
	}
	
	public void shutdown() {
	}
	

	// Outputs the maximum, minimum, and average ping times 
	private void outputFinalResults(int[] pingTimes){
		
		if (pingTimes.length > 0){
			int max = 0;
			int min = 0; 
			int sum = 0;
			int avg;
			
			for (int i = 0; i < pingTimes.length; i++){
				int time = pingTimes[i];
				
				if (i == 0){
					max = time;
					min = time;
				} else {
					max = Math.max(max, time);
					min = Math.min(min, time);
				}
				sum += time;
			}
			
			avg = sum / pingTimes.length;
			
			System.out.println("Maximum = " + max + "ms,\tMinimum = " + min + "ms,\tAverage = " + avg + "ms");
		}
	}
}
